package com.sparrow.common.aoi.impl.ninegrid;

import com.sparrow.common.aoi.AbstractAOISystem;
import com.sparrow.common.aoi.domain.AOIEntity;
import com.sparrow.common.aoi.domain.Area;
import com.sparrow.common.aoi.domain.EntityType;
import com.sparrow.common.aoi.domain.MapData;
import com.sparrow.common.aoi.listener.AOIListener;
import com.sparrow.common.aoi.util.MapUtil;
import java.util.*;

/**
 * 九宫格AOI实现
 */
public class NineGridAOISystem extends AbstractAOISystem {

    @Override
    public Collection<AOIEntity> queryAOIEntity(AOIMap map, int x, int y) {
        Set<AOIEntity> results = new HashSet<>();
        Set<Area> roundArea = MapUtil.getRoundAreaByGrid(map, x, y);
        for (Area area : roundArea) {
            for (Map.Entry<EntityType, Map<Long, AOIEntity>> e : area.getEntityMap().entrySet()) {
                results.addAll(e.getValue().values());
            }
        }
        return results;
    }

    @Override
    public void addAOIEntity(AOIMap map, AOIEntity aoiEntity, int x, int y) {
        aoiEntity.setAOIX(x);
        aoiEntity.setAOIY(y);
        MapData mapData = map.getMapData();
        int areaId = MapUtil.getAreaByGrid(mapData, aoiEntity.getAOIX(), aoiEntity.getAOIY());
        Area curArea = map.getArea(areaId);
        if (curArea != null) {
            curArea.addEntity(aoiEntity);
        }
        Set<Area> roundArea = MapUtil.getRoundAreaByGrid(map, aoiEntity.getAOIX(), aoiEntity.getAOIY());
        for (Area area : roundArea) {
            if (area != null) {
                for (Map.Entry<EntityType, Map<Long, AOIEntity>> e : area.getEntityMap().entrySet()) {
                    for (AOIEntity ee : e.getValue().values()) {
                        for (AOIListener listener : listeners) {
                            if (ee.getAOIId() == aoiEntity.getAOIId()) {
                                continue;
                            }
                            listener.onEntityEnterView(map, ee, aoiEntity);
                        }
                    }
                }
            }
        }
    }

    @Override
    public void removeAOIEntity(AOIMap map, AOIEntity aoiEntity) {
        MapData mapData = map.getMapData();
        int areaId = MapUtil.getAreaByGrid(mapData, aoiEntity.getAOIX(), aoiEntity.getAOIY());
        Area curArea = map.getArea(areaId);
        if (curArea != null) {
            curArea.removeEntity(aoiEntity.getEntityType(), aoiEntity.getAOIId());
        }
        Set<Area> areas = MapUtil.getRoundAreaByGrid(map, aoiEntity.getAOIX(), aoiEntity.getAOIY());
        for (Area area : areas) {
            if (area != null) {
                for (Map.Entry<EntityType, Map<Long, AOIEntity>> e : area.getEntityMap().entrySet()) {
                    for (AOIEntity ee : e.getValue().values()) {
                        for (AOIListener listener : listeners) {
                            if (ee.getAOIId() == aoiEntity.getAOIId()) {
                                continue;
                            }
                            listener.onEntityLeaveView(map, ee, aoiEntity);
                            listener.onEntityLeaveView(map, aoiEntity, ee);
                        }
                    }
                }
            }
        }
    }

    @Override
    public void updateAOIEntityPosition(AOIMap map, AOIEntity aoiEntity, int x, int y) {
        MapData mapData = map.getMapData();
        int oldX = aoiEntity.getAOIX();
        int oldY = aoiEntity.getAOIY();
        int oldAreaId = MapUtil.getAreaByGrid(mapData, aoiEntity.getAOIX(), aoiEntity.getAOIY());
        int newAreaId = MapUtil.getAreaByGrid(mapData, x, y);

        if (oldAreaId != newAreaId) {
            // 获取旧区域
            Area oldArea = map.getArea(oldAreaId);
            if (oldArea != null) {
                oldArea.removeEntity(aoiEntity);
            }
            // 获取新区域
            Area newArea = map.getArea(newAreaId);
            if (newArea != null) {
                newArea.addEntity(aoiEntity);
            }
        }

        // 更新实体坐标
        aoiEntity.setAOIX(x);
        aoiEntity.setAOIY(y);

        //广播逻辑
        Set<Area> oldAreas = MapUtil.getRoundAreaByGrid(map, oldX, oldY);
        Set<Area> curAreas = MapUtil.getRoundAreaByGrid(map, x, y);
        for (Area area : oldAreas) {
            if (!curAreas.contains(area)) {
                //旧区域视野移除
                for (Map.Entry<EntityType, Map<Long, AOIEntity>> e : area.getEntityMap().entrySet()) {
                    for (AOIEntity ee : e.getValue().values()) {
                        if (ee.getAOIId() != aoiEntity.getAOIId()) {
                            for (AOIListener listener : listeners) {
                                listener.onEntityLeaveView(map, ee, aoiEntity);
                                listener.onEntityLeaveView(map, aoiEntity, ee);
                            }
                        }
                    }
                }
            }
        }
        for (Area area : curAreas) {
            if (!oldAreas.contains(area)) {
                //新区域视野出现
                for (Map.Entry<EntityType, Map<Long, AOIEntity>> e : area.getEntityMap().entrySet()) {
                    for (AOIEntity ee : e.getValue().values()) {
                        if (ee.getAOIId() != aoiEntity.getAOIId()) {
                            for (AOIListener listener : listeners) {
                                listener.onEntityEnterView(map, ee, aoiEntity);
                                listener.onEntityEnterView(map, aoiEntity, ee);
                            }
                        }
                    }
                }
            }
            //位置变化通知
            for (Map.Entry<EntityType, Map<Long, AOIEntity>> e : area.getEntityMap().entrySet()) {
                for (AOIEntity ee : e.getValue().values()) {
                    for (AOIListener listener : listeners) {
                        listener.onEntityPositionChange(map, ee, aoiEntity);
                    }
                }
            }
        }
    }

}
